package mrusanov.localization

import mrusanov.log.Log
import io.{Codec, Source}
import java.net.URI

object Localization extends Log {

  lazy val messages: Map[String, Map[String, String]] = initMessages()

  private val MessageSeparator = "="
  private val ParamHolder = "%s"

  //TODO move to Configuration
  private val defaultLanguage = "en"
  private val currentLanguage = "en"
  private val filenamePattern = "localization/messages"
  private val languages = List("en", "uk", "ru")

  def apply(key: String, params: Any*)(implicit lang: String = currentLanguage): String = {
    messages.get(lang) match {
      case Some(messageMap) => getMessage(messageMap, key, params:_*)
      case None => apply(key, params:_*)(defaultLanguage)
    }
  }

  private def getMessage(messageMap: Map[String, String], key: String, params: Any*) = {
    messageMap.get(key) match {
      case Some(message) => putParamsInMessage(message, params:_*)
      case None => key
    }
  }

  private def putParamsInMessage(message: String, params: Any*) = {
    params.foldLeft(message) ((msg, p) =>
      msg.replaceFirst(ParamHolder, p.toString))
  }

  private def initMessages(): Map[String, Map[String, String]] = {
    logger.debug("loading messages.en for following languages: " + languages.mkString(","))

    val loadedMessages = languages.foldLeft(Map.empty[String, Map[String, String]]) {
      (map, lang) => map + (lang -> parseMessages(lang))
    }

    loadedMessages foreach {case (lang, map) => logger.info("For language {} found {} messages.en.en", lang, map.size)}
    loadedMessages
  }


  private def parseMessages(language: String): Map[String, String] = {
    val fileName = filenamePattern + "." + language
    val resource = getClass.getClassLoader.getResource(fileName)
    parseLines(resource.toURI)
  }

  private def parseLines(resourceUri: URI) = {
    implicit def parseLine(line: String) = new {
      def separatorIndex = line.indexOf(MessageSeparator)
      def key = line.take(separatorIndex)
      def message = line.drop(separatorIndex + MessageSeparator.size)
    }

    val lines = Source.fromFile(resourceUri)(Codec("UTF-8")).getLines()
    lines.map(line => (line.key, line.message)).toMap
  }
}
